package com.hockeo.tinygds.error;

import java.lang.reflect.Field;

import com.extjs.gxt.charts.client.model.Text;
import com.hockeo.tinygds.TKey;
import com.hockeo.tinygds.annotation.TEntity;
import com.hockeo.tinygds.annotation.TId;
import com.hockeo.tinygds.annotation.TName;
import com.hockeo.tinygds.annotation.TParent;
import com.hockeo.tinygds.annotation.TUnindexed;

/**
 * Indicates that an operation was attempted on a class, a key or an object that is not
 * linked to a persistable entity or that a persistable class/object is not correctly
 * configured to work with TinyGDS.
 *
 * @version $Id$
 * @author jjanke
 */
public class TNotPersistableException extends TinyGDSException
{
  private static final long serialVersionUID = 1L;

  /**
   * Creates a new exception. This constructor is private in order to force the user to
   * use one of the static factory methods.
   *
   * @param strMsg the exception message
   */
  private TNotPersistableException( String strMsg )
  {
    super( strMsg );
  }

  public static TNotPersistableException classNotAnnotatedWithEntity( Class<?> cls )
  {
    return new TNotPersistableException( "The class '" + cls.getName()
        + "' is not persistable as it is not annotated with '" + TEntity.class.getName() + "'." );
  }

  public static TNotPersistableException tooManyIds( Class<?> cls )
  {
    return new TNotPersistableException( "The class '" + cls.getName()
        + "' incl. its super classes defines more than one field annotated with @'" + TId.class.getName() + "'." );
  }

  public static TNotPersistableException tooManyParents( Class<?> cls )
  {
    return new TNotPersistableException( "The class '" + cls.getName()
        + "' incl. its super classes defines more than one field annotated with @'" + TParent.class.getName() + "'." );
  }

  public static TNotPersistableException noIdField( Class<?> cls )
  {
    return new TNotPersistableException( "The class '" + cls.getName()
        + "' incl. its super classes does not define a field with the annotation @'" + TId.class.getName() + "'." );
  }

  public static TNotPersistableException noArgumentLessConstructor( Class<?> cls )
  {
    return new TNotPersistableException( "The class '" + cls.getName()
        + "' incl. its super classes does not define an argument-less constructor." );
  }

  public static TNotPersistableException wrongIdType( Field field )
  {
    return new TNotPersistableException( "The field '" + getFieldName( field ) + "' is annotated with @'"
        + TId.class.getName() + "' but does not have the type Long, long or String." );
  }

  public static TNotPersistableException wrongParentType( Field field )
  {
    return new TNotPersistableException( "The field '" + getFieldName( field ) + "' is annotated with @'"
        + TParent.class.getName() + "' but does not have the type '" + TKey.class.getName() + "'." );
  }

  public static TNotPersistableException unsupportedFieldType( Field field )
  {
    return new TNotPersistableException( "The type '" + field.getType().getName() + "' of the field '"
        + getFieldName( field ) + "' is not supported by the Google Datastore. If the field should "
        + "not be persisted, declare it as transient." );
  }

  public static TNotPersistableException annotationTNameWithoutValue( Field field )
  {
    return new TNotPersistableException( "The annotation '" + TName.class.getName() + "' of the field '"
        + getFieldName( field ) + "' has not value set." );
  }

  public static TNotPersistableException tooManyPropertiesWithSameName( Class<?> cls, String strName )
  {
    return new TNotPersistableException( "The class '" + cls.getName()
        + "' incl. its super classes defines more than one field with the property name '" + strName
        + "'. Please use the '" + TName.class.getName() + "' annotation to assign unique names." );
  }

  public static TNotPersistableException objectHasNullStringId( Field field, Object obj )
  {
    return new TNotPersistableException( "The @TId field '" + getFieldName( field ) + "' of the object '"
        + obj.toString() + "' has a null value." );
  }

  public static TNotPersistableException indexedStringPropertyTooLong( Field field, String strVal )
  {
    return new TNotPersistableException( "The indexed field '" + getFieldName( field ) + "' has the value '" + strVal
        + "' which is too long for the Google datastore. It needs to be converted into a '" + Text.class.getName()
        + "' object which is always unindexed. Either change the object's value or annotate the field with '"
        + TUnindexed.class.getName() + "'." );
  }

  private static String getFieldName( Field field )
  {
    return field.getDeclaringClass().getName() + "#" + field.getName();
  }
}
